package com.karry.commons.util;


import org.ponly.fs.util.IOUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 下载视图
 *
 * @author vacoor
 */
@SuppressWarnings("unused")
public abstract class DownloadView {
    public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
    private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private String filename;        // 下载的文件名称
    private String contentType;     // content type
    private boolean attachment;    // 是否是附件

    /**
     * 创建一个下载视图
     *
     * @param filename 下载文件名称
     */
    public DownloadView(String filename) {
        this(filename, true);
    }

    /**
     * 创建一个下载视图
     *
     * @param filename    文件名称
     * @param contentType 文件 MIME 类型
     */
    public DownloadView(String filename, String contentType) {
        this(filename, contentType, true);
    }

    /**
     * 创建一个下载视图
     *
     * @param filename   文件名称
     * @param attachment 是否附件 (attachment/inline)
     */
    public DownloadView(String filename, boolean attachment) {
        this(filename, null, attachment);
    }

    public DownloadView(String filename, String contentType, boolean attachment) {
        this.filename = filename;
        this.contentType = contentType;
        this.attachment = attachment;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public boolean isAttachment() {
        return attachment;
    }

    public void setAttachment(boolean attachment) {
        this.attachment = attachment;
    }

    /* *************************
     *
     * *************************/

    /*
    public final void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        doDownload(request, response, getInputStream(), filename, contentType, attachment);
    }
    */
   /* public void sendTo(WebRequestContext context) throws IOException {
        sendTo(context.getRequest(), context.getResponse());
    }*/

    public void sendTo(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doDownload(request, response);
    }

    protected void doDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // response.reset();
        if (!attachment) {  // inline
            response.setHeader("Content-Disposition", "inline");
        } else {
            /*-
             * RFC2231:  parameter*=charset'lang'value (filename*=encoding''...):
             * 支持情况:
             * RFC2231:    ie 8, chrome 17, opera 11, firefox 11
             * ISO-8859-1: chrome, opera, firefox, safari
             * URLEncode:  IE6+, chrome
             * Base64:     chrome, firefox
             * 最主要的问题是 IE 和 Firefox 无法同时兼容
             */
            StringBuilder buff = new StringBuilder();
            buff.append("attachment; ")
                    .append("filename=");

            String filename = null != this.filename ? this.filename : new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

            /*
            // IE6, IE7
            if (request.getHeader("User-Agent").contains("MSIE")) {
                buff.append(URLEncoder.encode(filename, UTF_8.name()));
            } else {
                buff.append(new String(filename.getBytes(UTF_8), ISO_8859_1)).append("; ");
            }
            */
            // 大部分浏览器已经支持 filename*=utf-8''filename, 因此的filename只考虑 IE
            buff.append(URLEncoder.encode(filename, UTF_8.name()));
            buff.append("; ");

            String fname = filename;
            try {
                fname = URLEncoder.encode(fname, UTF_8.name());
            } catch (UnsupportedEncodingException ignore) { /*ignore*/ }
            buff.append("filename*=utf-8''").append(fname);

            response.setHeader("Content-Disposition", buff.toString());
        }

        /*if (!StringUtils.hasText(contentType) && null != request) {
            contentType = request.getServletContext().getMimeType(filename);
        }
        if (!StringUtils.hasText(contentType)) {
            contentType = DEFAULT_CONTENT_TYPE;
        }
        response.setContentType(contentType);*/

        try {
            doDownloadInternal(request, response);
        } catch (IOException e) {
            response.setHeader("Content-Type", "text/html");
            response.setHeader("Content-Disposition", null);
            // response.reset();
        }
    }

    protected void doDownloadInternal(HttpServletRequest request, HttpServletResponse response) throws IOException {
        InputStream is = getResourceAsStream();
        try {
            if (null == is) {
                response.reset();
                response.sendError(404);
            } else {
                IOUtil.flow(is, response.getOutputStream(), true, false);
            }
        } finally {
            IOUtil.close(is);
        }
    }

    protected abstract InputStream getResourceAsStream();
}